﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace DbView
{
	public partial class LookupEditForm : Form
	{
		LookupEditController controller;
		bool updating = false;

		public LookupEditForm(LookupEditController controllerIn)
		{
			InitializeComponent();
			this.SetHelp();
			this.controller = controllerIn;
			// register self as the view with the controller
			this.controller.View = this;
			// set up bindings of control properties to properties in the model or controller
			InitialiseBindings();
			if (!string.IsNullOrEmpty(this.controller.Model.Table))
			{
				this.comboSourceTable.Enabled = false;
				this.comboSourceField.Enabled = false;
			}
		}
		
		void InitialiseBindings()
		{
			this.comboSourceTable.DataBindings.Add("Text", this.controller.Model, "Table", false, DataSourceUpdateMode.OnPropertyChanged);
			this.comboSourceField.DataBindings.Add("Text", this.controller.Model, "Field", false, DataSourceUpdateMode.OnPropertyChanged);
			this.comboLookupTable.DataBindings.Add("Text", this.controller.Model, "LookupTable", false, DataSourceUpdateMode.OnPropertyChanged);
			this.comboLookupField.DataBindings.Add("Text", this.controller.Model, "LookupField", false, DataSourceUpdateMode.OnPropertyChanged);
			// selection bindings
			this.listFields.DataBindings.Add("SelectedItem", this.controller, "LookupFieldSelection", false, DataSourceUpdateMode.OnPropertyChanged);
			this.listSelected.DataBindings.Add("SelectedItem", this.controller, "SelectedLookupsSelection", false, DataSourceUpdateMode.OnPropertyChanged);
			this.textFilter.DataBindings.Add("Text", this.controller, "Filter", false, DataSourceUpdateMode.OnPropertyChanged);
		}

		private void LookupEditForm_Load(object sender, EventArgs e)
		{
			this.updating = true;
			this.controller.SetFormInitialState();
			this.updating = false;
		}
		
		private void btnSave_Click(object sender, EventArgs e)
		{
			if (this.controller.CommitChangesToModel())
			{
				this.DialogResult = System.Windows.Forms.DialogResult.OK;
				this.Close();
			}
			else
			{
				// get error and message box
				MessageBox.Show(this.controller.GetLastError(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
			}
		}

		private void btnCancel_Click(object sender, EventArgs e)
		{
			OnCloseWithNoAction();
		}


		private void textFilter_TextChanged(object sender, EventArgs e)
		{
			if (this.updating) return;
			this.updating = true;
			TextBox t = sender as TextBox;
			// Because focus not lost as text is entered.
			if (t != null)
				t.DataBindings[0].WriteValue();
			this.controller.OnFilterChanged();
			this.updating = false;
		}
	
		private void combolookupTable_SelectedValueChanged(object sender, EventArgs e)
		{
			// best so far
			if (this.updating) return;
			this.updating = true;
			this.controller.OnLookupTableSelected();
			this.updating = false;
		}

		private void comboSourceTable_SelectedValueChanged(object sender, EventArgs e)
		{
			if (this.updating) return;
			this.updating = true;
			// best so far
			this.controller.OnSourceTableSelected();
			this.updating = false;
		}

		private void btdAdd_Click(object sender, EventArgs e)
		{
			if (this.updating) return;
			this.updating = true;
			this.controller.OnAdd();
			this.updating = false;
		}

		private void listFields_MouseDoubleClick(object sender, MouseEventArgs e)
		{
			if (this.updating) return;
			this.updating = true;
			(sender as ListControl).DataBindings[0].WriteValue();
			this.controller.OnAdd();
			this.updating = false;
		}

		private void btnRemove_Click(object sender, EventArgs e)
		{
			if (this.updating) return;
			this.updating = true;
			this.controller.OnDelete();
			this.updating = false;
		}

		private void btnReset_Click(object sender, EventArgs e)
		{
			if (this.updating) return;
			this.updating = true;
			this.controller.ClearFilter();
			this.updating = false;
		}

		private void btnMoveUp_Click(object sender, EventArgs e)
		{
			this.controller.OnMoveUp();
		}

		private void btnMoveDown_Click(object sender, EventArgs e)
		{
			this.controller.OnMoveDown();
		}
		
		private void OnCloseWithNoAction()
		{
			this.DialogResult = DialogResult.Cancel;
			this.Close();
		}

		////////////////////////////////////////////////////////////////////////////////////////////
		// API for controller
		
		// Update the left pick list when initialising, adding or deleting
		public void RefreshLookupTable(List<string> source)
		{
			ListControl ctrlList = this.comboLookupTable;
			string holdSelection = ctrlList.Text;
			this.RefreshSource(ctrlList, source, null);
			ctrlList.Text = holdSelection;
		}
		public void RefreshSourceTable(List<string> source)
		{
			ListControl ctrlList = this.comboSourceTable;
			string holdSelection = ctrlList.Text;
			this.RefreshSource(ctrlList, source, null);
			ctrlList.Text = holdSelection;
		}
		public void RefreshLookupField(List<string> source)
		{
			this.RefreshCombo(this.comboLookupField, source);
			return;
		}
		public void RefreshSourceField(List<string> source)
		{
			ListControl ctrlList = this.comboSourceField;
			this.RefreshSource(ctrlList, source, null);
		}

		private void RefreshCombo(ListControl ctrlList, List<string> source)
		{
			string holdSelection = ctrlList.Text;
			this.RefreshSource(ctrlList, source, null);
			if (!string.IsNullOrEmpty(holdSelection))
				ctrlList.Text = holdSelection;
		}

		//////////////////////////////////////////////////////////////////////
		// Report field selection. Code from sample
		// Update the left pick list when initialising, adding or deleting
		public void RefreshSelectionFields(List<string> source)
		{
			ListControl ctrlList = this.listFields;
			this.RefreshSource(ctrlList, source, null);
			ctrlList.DataBindings[0].ReadValue();
		}

		// Update the right pick list when initialising, adding or deleting
		public void RefreshSelectedFields(List<string> source)
		{
			ListControl ctrlList = this.listSelected;
			this.RefreshSource(ctrlList, source, null);
			ctrlList.DataBindings[0].ReadValue();
		}

		////////////////////////////////////////////////////////////////////////////////////////////
		// Helper for the above
		private void RefreshSource(ListControl ctrlList, object source, string displayPropertyName)
		{
		    // if the source is the same as what is sent in then undo it to 
		    // force a refresh
		    if (ctrlList.DataSource == source)
		        ctrlList.DataSource = null;
		    ctrlList.DataSource = source;
		    if (!string.IsNullOrEmpty(displayPropertyName))
		        ctrlList.DisplayMember = displayPropertyName;
		}

		private void SetHelp()
		{
			string message = "Use this form to create a lookup link from a field in a source table to a lookup table. "+
							"When you right click on a source field in a data grid it will display data relating to the "+
							"value or values from the lookup table.\n" +
							"eg. the source table is one that contains a foreign key. The source field is the foreign key. "+
							"The lookup table contains the primary key linked to the foreign key. Select fields from the lookup table for display.";
			this.labelHelp.Text = message;
		}
	}

	public class LookupModel
	{
		// source of the data to be looked-up
		public string Table {get; set; }
		public string Field {get; set; }
		// where the data is held
		public string LookupTable {get; set; }
		public string LookupField {get; set; }
		public string FieldType {get; set; }   // for return only. Don't count on it being set
		// Fields selected from the Lookup table for display
		public List<string> SelectedFields {get { return l1; } }
		public List<string> l1 = new List<string>();

		public LookupModel()
		{
			this.Table = "";
			this.Field = "";
			this.LookupTable = "";
			this.LookupField = "";
			this.FieldType = "";
		}

		public LookupModel(LookupModel source)
		{
			this.Copy(source);
		}

		public void Copy(LookupModel source)
		{
			this.Table = source.Table;
			this.Field = source.Field;
			this.LookupTable = source.LookupTable;
			this.LookupField = source.LookupField;
			this.FieldType = source.FieldType;
			this.SelectedFields.Clear();
			this.SelectedFields.AddRange(source.SelectedFields);
		}

		public override bool  Equals(object obj)
		{
 			LookupModel other = obj as LookupModel;
			if (other == null) return false;
			if (other.Table != this.Table) return false;
			if (other.Field != this.Field) return false;
			if (other.LookupTable != this.LookupTable) return false;
			if (other.LookupField != this.LookupField) return false;
			if (other.FieldType != this.FieldType) return false;
			if (!this.SequenceEqual(this.SelectedFields, other.SelectedFields)) return false;
			return true;
		}

		bool SequenceEqual(List<string> l1, List<string> l2)
		{
			if (l1.Count != l2.Count) return false;
			for (int idx = 0; idx < l1.Count; ++idx)
				if (!l1[idx].Equals(l2[idx]))
					return false;
			return true;
		}

		public override string ToString()
		{
			string list = string.Join(", ", this.SelectedFields.ToArray());
			return string.Format("{0}.{1} -> {2}.{3}\n{4}", this.Table, this.Field, this.LookupTable, this.LookupField, list);
		}

		public static LookupModel DataTransfer(DbView.Resources.LookupInfo.Key key, DbView.Resources.LookupInfo.Data data)
		{
			LookupModel model = new LookupModel();
			model.Table = key.Table;
			model.Field = key.Field;
			// if creating a model for adding a new lookup
			if (data != null)
			{
				model.LookupTable = data.PkTable;
				model.LookupField = data.PkField;
				foreach (string field in data.ReportFields)
					model.SelectedFields.Add(field);
			}
			return model;
		}

		// key needs to be populated with the driver and connection
		public static DbView.Resources.LookupInfo.Data DataTransfer(LookupModel model, DbView.Resources.LookupInfo.Key key)
		{
			DbView.Resources.LookupInfo.Data data = new Resources.LookupInfo.Data();
			key.Table = model.Table;
			key.Field = model.Field;
			data.PkTable = model.LookupTable;
			data.PkField = model.LookupField;
			foreach (string field in model.SelectedFields)
				data.AddReportField(field);
			return data;
		}
	}
}
